#include <iostream>

#include <vector>
#include <functional>
#include <chrono>
#include <thread>
#include <mutex>

using namespace std;
typedef struct worker {
    thread *thd;
    int runflag;
}Worker_t;
typedef struct manager {
    thread *thd;
    int task_number;
    vector<Worker_t*> workers; 
    int runflag;
}Manager_t;
int thread_func1(Worker_t *worker)
{
    int runflag;
    while (worker->runflag) {
        cout << "current thread id:" << this_thread::get_id() << endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
    cout << "thread:" << this_thread::get_id() << " out" << endl;
    return 0;
}
int thread_manager(Manager_t *manager)
{
    int tasknumber;
    thread *tmp;
    Worker_t *worker;
    this_thread::sleep_for(chrono::seconds(20));
    while (manager->runflag) {
        cout << "manager is running:" << this_thread::get_id() << endl;
        cout << "current thread number is:" << manager->workers.size() << endl;
        cout << "current task number is:" << manager->task_number << endl;
        if (manager->task_number > manager->workers.size()) {
            worker = new Worker_t();
            worker->runflag = 1;
            worker->thd = new thread(thread_func1, worker);
            manager->workers.push_back(worker);
            cout << "add a thread.." << endl;
        } else if (manager->task_number < manager->workers.size()){
            if (manager->workers.size()!=0) {
                worker = manager->workers.at(manager->workers.size()-1);
                manager->workers.pop_back();
                if (worker->thd->joinable()) {
                    worker->runflag = 0;
                    worker->thd->join();
                    delete worker->thd;
                    delete worker;
                    cout << "dec a thread.." << endl;
                }
            }
        } else {
            cout << "task number is equal thread number" << endl;
        }
        this_thread::sleep_for(chrono::seconds(2));
    }
    cout << "manager thread is out" << endl;
}

class Worker {
    private:
        Worker_t *m_worker;
        int init_flag;
        int worker_func(Worker_t *worker);
    public:
        Worker();
        virtual ~Worker();
};

class Manager {
    private:
        Manager_t *m_manager;
        int init_flag;
        vector<Worker*> workers;
        int manager_func(Manager_t *manager);
    public:
        int set_task_number(int number){m_manager->task_number = number;}
        int stop(){}
        Manager(int worker_number, int task_number);
        virtual ~Manager();
};

Manager::Manager(int worker_number, int task_number)
{
    Worker *worker;
    thread *tmp;
    m_manager = new Manager_t;
    
    if (m_manager!=NULL) {
        m_manager->runflag = 1;
        for (int i = 0; i < worker_number; i++) {
            worker = new Worker();
            if (worker!=NULL) {
                workers.push_back(worker);
                m_manager->task_number++;
                cout << "add one thread..." << endl;
            }
        }
    }
    m_manager->thd = new thread(bind(&Manager::manager_func, this, m_manager));
    init_flag = 1;
}

Manager::~Manager()
{
    Worker *worker;
    m_manager->runflag = 0;
    if (init_flag) {
        for (int i = 0, size = workers.size(); i < size; i++) {
            worker = workers.at(workers.size()-1);
            workers.pop_back();
            delete worker;
        }
        workers.clear();
    } else {

    }
    init_flag = 0;
    if (m_manager->thd->joinable()) {
        m_manager->thd->join();
        delete m_manager->thd;
        delete m_manager;
    }
    cout << "manager end.." << endl;
}

int Manager::manager_func(Manager_t *m)
{
    Worker *worker;
    if (init_flag) {
        cout << "manager thread is running..." << endl;
        while (m_manager->runflag) {
            this_thread::sleep_for(chrono::seconds(2));
            cout << "thread:" << this_thread::get_id() << endl;
            if (m_manager->task_number > workers.size()) {
                worker = new Worker();
                if (worker) {
                    cout << "add a thread.." << endl;
                    workers.push_back(worker);
                }
            } else if (m_manager->task_number < workers.size()) {
                worker = workers.at(workers.size()-1);
                workers.pop_back();
                if (worker) {
                    cout << "dec a thread.." << endl;
                    delete worker;
                }
            } else {
                cout << "task number is equeal worker size." << endl;
            }
        }
        cout << "manager thread out" << endl;
    } else {
        return -1;
    }
    return 0;
}

int Worker::worker_func(Worker_t *worker)
{
    if (!worker || !init_flag)
        return -1;
    else 
        thread_func1(worker);
    return 0;
}

Worker::Worker()
{
    init_flag = 0;
    m_worker = new Worker_t;
    if (m_worker)
        init_flag = 1;
    m_worker->runflag = 1;
    m_worker->thd = new thread(bind(&Worker::worker_func, this, m_worker));
}

Worker::~Worker()
{
    init_flag = 0;
    m_worker->runflag = 0;
    if (m_worker->thd!=NULL) {
        if (m_worker->thd->joinable()) {
            m_worker->thd->join();
            delete m_worker->thd;
        }
    }
    delete m_worker;
}

vector<thread*> thread_pool;
int runflag = 1;
int tasknumber = 0;
int main(int argc, char **argv)
{
    int task_number = 10;
    Manager manager(10, task_number);
#if 0
    Manager_t  m_manager;
    Worker_t  *worker;
    thread *tmp;
    for (int i = 0; i < 10; i++) {
        worker = new Worker_t;
        worker->runflag = runflag;
        tmp = new thread(bind(thread_func1, worker));
        worker->thd = tmp;
        m_manager.workers.push_back(worker);
    }
    m_manager.task_number=5;
    m_manager.thd = new thread(bind(thread_manager, &m_manager));
#endif
    char opt;
    while (1) {
        opt = getchar();
        if (opt == '\n')
            continue;
        switch (opt) {
            case 'q':
                break;
            case 'a':
                task_number++;
                manager.set_task_number(task_number);
                break;
            case 'd':
                task_number--;
                manager.set_task_number(task_number);
                break;
        }
        if (opt=='q')
            break;
    }
#if 0
    m_manager.runflag = 0;
    for (int i = 0, size = m_manager.workers.size(); i < size; i++) {
        worker = m_manager.workers.at(m_manager.workers.size()-1);
        m_manager.workers.pop_back();
        worker->runflag = 0;
        if (worker) {
            if (worker->thd->joinable()) {
                worker->thd->join();
                delete worker->thd;
                delete worker;
            }
        }

        cout << "a thread end..." << endl;
    }
    m_manager.workers.clear();
    m_manager.thd->join();
    delete m_manager.thd;
#endif
    return 0;
}
